package com.microframework.base.core.util;

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * 等保三级加密工具类
 * 提供符合等保三级要求的加密算法:
 * 1. 对称加密：AES-256-GCM/CBC
 * 2. 非对称加密：RSA-2048
 * 3. 哈希算法：SHA-256/SHA-512
 * 4. 密码加密：BCrypt
 * 5. HMAC：HmacSHA256
 */
public class EncryptUtil {
    
    private static final String AES_ALGORITHM = "AES";
    private static final String AES_CBC_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String RSA_ALGORITHM = "RSA";
    private static final String RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding";
    private static final String SHA256_ALGORITHM = "SHA-256";
    private static final String SHA512_ALGORITHM = "SHA-512";
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
    private static final int AES_KEY_SIZE = 256;
    private static final int RSA_KEY_SIZE = 2048;
    private static final int BCRYPT_STRENGTH = 12;
    private static PasswordEncoder PASSWORDENCODER = PasswordEncoderFactories.createDelegatingPasswordEncoder();
    private static final BCryptPasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder(BCRYPT_STRENGTH);
    private static final BCryptPasswordEncoder ENCODER = new BCryptPasswordEncoder();
    
    /**
     * 密码校验
     *
     * @param raw String 原始密码
     * @param encodePassword String 加密后的密码
     * @return true | false
     */
    public static boolean matches(String raw, String encodePassword) {
        return PASSWORDENCODER.matches(raw, encodePassword);
    }
    
    /**
     * AES加密
     * 
     * @param plainText 明文
     * @param key AES密钥 (必须是16/24/32字节长度)
     * @param iv 初始化向量 (16字节)
     * @return 加密后的Base64编码字符串
     */
    public static String aesEncrypt(String plainText, String key, String iv) {
        try {
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
            byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
            
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
            
            Cipher cipher = Cipher.getInstance(AES_CBC_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("AES加密失败", e);
        }
    }
    
    /**
     * AES解密
     * 
     * @param encryptedText Base64编码的密文
     * @param key AES密钥 (必须是16/24/32字节长度)
     * @param iv 初始化向量 (16字节)
     * @return 解密后的明文
     */
    public static String aesDecrypt(String encryptedText, String key, String iv) {
        try {
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
            byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
            
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
            
            Cipher cipher = Cipher.getInstance(AES_CBC_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("AES解密失败", e);
        }
    }
    
    /**
     * 生成AES密钥
     * 
     * @return Base64编码的AES密钥
     */
    public static String generateAesKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
            keyGenerator.init(AES_KEY_SIZE, new SecureRandom());
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("生成AES密钥失败", e);
        }
    }
    
    /**
     * 生成RSA密钥对
     * 
     * @return RSA密钥对数组 [0]=公钥 [1]=私钥 (Base64编码)
     */
    public static String[] generateRsaKeyPair() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
            keyPairGenerator.initialize(RSA_KEY_SIZE, new SecureRandom());
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            
            String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
            String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
            
            return new String[] { publicKey, privateKey };
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("生成RSA密钥对失败", e);
        }
    }
    
    /**
     * RSA公钥加密
     * 
     * @param plainText 明文
     * @param publicKeyBase64 Base64编码的公钥
     * @return Base64编码的密文
     */
    public static String rsaEncrypt(String plainText, String publicKeyBase64) {
        try {
            byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            
            Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("RSA加密失败", e);
        }
    }
    
    /**
     * RSA私钥解密
     * 
     * @param encryptedText Base64编码的密文
     * @param privateKeyBase64 Base64编码的私钥
     * @return 解密后的明文
     */
    public static String rsaDecrypt(String encryptedText, String privateKeyBase64) {
        try {
            byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyBase64);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            
            Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("RSA解密失败", e);
        }
    }
    
    /**
     * 使用SHA-256哈希算法
     * 
     * @param data 需要哈希的数据
     * @return 哈希值的十六进制字符串
     */
    public static String sha256(String data) {
        try {
            MessageDigest digest = MessageDigest.getInstance(SHA256_ALGORITHM);
            byte[] hashBytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(hashBytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA-256哈希失败", e);
        }
    }
    
    /**
     * 使用SHA-512哈希算法
     * 
     * @param data 需要哈希的数据
     * @return 哈希值的十六进制字符串
     */
    public static String sha512(String data) {
        try {
            MessageDigest digest = MessageDigest.getInstance(SHA512_ALGORITHM);
            byte[] hashBytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(hashBytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA-512哈希失败", e);
        }
    }
    
    /**
     * 使用BCrypt算法加密密码
     * 
     * @param password 明文密码
     * @return 加密后的密码
     */
    public static String encryptPassword(String password) {
        return PASSWORD_ENCODER.encode(password);
    }
    
    /**
     * 验证BCrypt加密的密码
     * 
     * @param rawPassword 明文密码
     * @param encodedPassword 加密后的密码
     * @return 是否匹配
     */
    public static boolean verifyPassword(String rawPassword, String encodedPassword) {
        return ENCODER.matches(rawPassword, encodedPassword);
    }
    
    /**
     * HMAC-SHA256算法
     * 
     * @param data 需要认证的数据
     * @param key 密钥
     * @return HMAC值的十六进制字符串
     */
    public static String hmacSha256(String data, String key) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA256_ALGORITHM);
            Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
            mac.init(secretKeySpec);
            byte[] hmacBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(hmacBytes);
        } catch (Exception e) {
            throw new RuntimeException("HMAC-SHA256计算失败", e);
        }
    }
    
    /**
     * 字节数组转十六进制字符串
     * 
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder(2 * bytes.length);
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
    
    /**
     * 生成安全随机数
     * 
     * @param length 随机数长度
     * @return Base64编码的随机数
     */
    public static String generateSecureRandom(int length) {
        byte[] randomBytes = new byte[length];
        try {
            SecureRandom secureRandom = SecureRandom.getInstanceStrong();
            secureRandom.nextBytes(randomBytes);
            return Base64.getEncoder().encodeToString(randomBytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("生成安全随机数失败", e);
        }
    }
    
    /**
     * 生成16字节IV向量
     * 
     * @return Base64编码的IV向量
     */
    public static String generateIv() {
        return generateSecureRandom(16);
    }
    
    /**
     * 密码加密
     *
     * @param raw String 原始密码
     * @return String 加密后的密码
     */
    public static String encrypt(String raw) {
        return PASSWORDENCODER.encode(raw);
    }
    
    public static void main(String[] args) {

    	String encodedPassword=encryptPassword("rs@123");
    	System.out.println(encodedPassword);
    	//System.out.println(verifyPassword("rs@123",  encodedPassword));
    	
    	// 创建编码器
    	BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    	// 注册时加密存储
    	//String storedHash = encoder.encode("userPassword"); // 存储到数据库

    	// 登录时验证
    	boolean isMatch = encoder.matches("rs@123", "$2a$12$GQWflsFBKkO4CV/EC1AwQOnRMzxyu2tYC8Q/LaUd9SrVZqCYYTC3O");
    	System.out.println(isMatch);
	}
}
